/* -----------------------------------------------------------------------------
 * Copyright (c) 2014 - 2019 ARM Ltd.
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software. Permission is granted to anyone to use this
 * software for any purpose, including commercial applications, and to alter
 * it and redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *
 * $Date:        15. July 2019
 * $Revision:    V1.0.0
 *
 * Project:      Flash Programming Functions for ST STM32G0xx Flash
 * --------------------------------------------------------------------------- */

/* History:
 *  Version 1.0.0
 *    Initial release
 */

#include "..\FlashOS.h"        // FlashOS Structures

#include "Bsp.h"
#include "System.h"
#include "ExtFlash.h" 

typedef volatile unsigned long    vu32;
typedef          unsigned long     u32;

#define M32(adr) (*((vu32 *) (adr)))



// Flash Keys
//#define RDPRT_KEY                0x00A5
#define FLASH_KEY1               0x45670123
#define FLASH_KEY2               0xCDEF89AB
#define FLASH_OPTKEY1            0x08192A3B
#define FLASH_OPTKEY2            0x4C5D6E7F

// Flash Control Register definitions
#define FLASH_PG                ((unsigned int)(   1U <<  0))
#define FLASH_PER               ((unsigned int)(   1U <<  1))
#define FLASH_MER1              ((unsigned int)(   1U <<  2))
#define FLASH_PNB_MSK           ((unsigned int)(0x3FU <<  3))
#define FLASH_STRT              ((unsigned int)(   1U << 16))
#define FLASH_OPTSTRT           ((unsigned int)(   1U << 17))
#define FLASH_OBL_LAUNCH        ((unsigned int)(   1U << 27))
#define FLASH_OPTLOCK           ((unsigned int)(   1U << 30))
#define FLASH_LOCK              ((unsigned int)(   1U << 31))

// Flash Status Register definitions
#define FLASH_EOP               ((unsigned int)(   1U <<  0))
#define FLASH_OPERR             ((unsigned int)(   1U <<  1))
#define FLASH_PROGERR           ((unsigned int)(   1U <<  3))
#define FLASH_WRPERR            ((unsigned int)(   1U <<  4))
#define FLASH_PGAERR            ((unsigned int)(   1U <<  5))
#define FLASH_SIZERR            ((unsigned int)(   1U <<  6))
#define FLASH_PGSERR            ((unsigned int)(   1U <<  7))
#define FLASH_MISSERR           ((unsigned int)(   1U <<  8))
#define FLASH_FASTERR           ((unsigned int)(   1U <<  9))
#define FLASH_RDERR             ((unsigned int)(   1U << 14))
#define FLASH_OPTVERR           ((unsigned int)(   1U << 15))
#define FLASH_BSY               ((unsigned int)(   1U << 16))

#define FLASH_PGERR             (FLASH_OPERR  | FLASH_PROGERR | FLASH_PROGERR | FLASH_WRPERR  | FLASH_PGAERR | \
                                 FLASH_SIZERR | FLASH_PGSERR  | FLASH_MISSERR | FLASH_FASTERR | FLASH_RDERR  | \
                                 FLASH_OPTVERR                                                                )


/*
 * Get Sector Number
 *    Parameter:      adr:  Sector Address
 *    Return Value:   Sector Number
 */

#if defined FLASH_MEM
unsigned long GetSecNum (unsigned long adr) {
  unsigned long secNum;

  /* Single-Bank Flash */
  /* sector number 0..63 */
  secNum = ( (adr & 0x001FFFF) >> 11);

  return (secNum);                                      // Sector Number
}
#endif // FLASH_MEM


/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
	static int flags = 0;
	if(flags == 0)
	{
		SystemClock_Config();
		Bsp_Init();

//		DEBUG_MSG("Init Ok\r\n");
	}
	flags = 1;
  return (0);                                           // Done
}


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit (unsigned long fnc) {

//  DEBUG_MSG("UnInit\r\n");

  return (0);                                           // Done
}


/*
 *  Blank Check Checks if Memory is Blank
 *    Parameter:      adr:  Block Start Address
 *                    sz:   Block Size (in bytes)
 *                    pat:  Block Pattern
 *    Return Value:   0 - OK,  1 - Failed
 */

int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat) {

  /* force erase even if the content is 'Initial Content of Erased Memory'.
     Only a erased sector can be programmed. I think this is because of ECC */
//	DEBUG_MSG("BlankCheck\r\n");
  return (1);
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

#if defined FLASH_MEM
int EraseChip (void) {

//  DEBUG_MSG("EraseChip\r\n");

  return (0);                                           // Done
}
#endif // FLASH_MEM

/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

#ifdef FLASH_MEM
int EraseSector (unsigned long adr) {
  
//	DEBUG_MSG("EraseSector %X\r\n",adr);
	adr -= 0x90000000;
	ExtFlash_EraseSector(adr);
  return (0);                                           // Done
}
#endif // FLASH_MEM

/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

#if defined FLASH_MEM || defined FLASH_OTP
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {

  sz = (sz + 7) & ~7;                                   // Adjust size for two words

//  DEBUG_MSG("ProgramPage %X %X\r\n",adr,sz);                          // Reset Error Flags
	ExtFlash_WriteSector(adr-0x90000000,buf,4096);
//  while (sz) {
//                        

//    M32(adr    ) = *((u32 *)(buf + 0));                 // Program the first word of the Double Word
//    M32(adr + 4) = *((u32 *)(buf + 4));                 // Program the second word of the Double Word

////    while (FLASH->SR & FLASH_BSY) {
////    }

////    FLASH->CR  =  0;                                    // Reset CR

////    if (FLASH->SR & FLASH_PGERR) {                      // Check for Error
////      FLASH->SR  = FLASH_PGERR;                         // Reset Error Flags
////      return (1);                                       // Failed
////    }

//    adr += 8;                                           // Go to next DoubleWord
//    buf += 8;
//    sz  -= 8;
//  }

  return (0);                                           // Done
}
#endif // FLASH_MEM || FLASH_OTP

/*
 *  Verify Flash Contents
 *    Parameter:      adr:  Start Address
 *                    sz:   Size (in bytes)
 *                    buf:  Data
 *    Return Value:   (adr+sz) - OK, Failed Address
 */
unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf) {
 
//	DEBUG_MSG("Verify %X\r\n",adr); 
  return (adr + sz);
}

